/**
 * Anderground project - Subway maps processor application.
 * Copyright (C) 2008 Maksim Tkatchenko
 * Copyright (C) 2008-2009 Eldar Abusalimov, Ilya Shurigyn
 * 
 * This file is part of Anderground.
 * 
 * Anderground is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * Anderground is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Anderground.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.anderground.core.graphics;

import static java.lang.Math.pow;
import static java.lang.Math.sqrt;

import org.anderground.core.drawer.Calculator.Mode;
import org.anderground.core.util.Coord;
import org.anderground.core.util.Coordinated;

/**
 * 
 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
 * 
 */
public class PointF {

	public float x;

	public float y;

	public PointF() {
		set();
	}

	public PointF(PointF other) {
		set(other);
	}

	public PointF(float x, float y) {
		set(x, y);
	}

	public PointF(Coord coord) {
		set(coord);
	}

	public PointF(Coordinated coordinated, Mode mode) {
		set(coordinated, mode);
	}

	public void set() {
		this.x = 0;
		this.y = 0;
	}

	public void set(PointF another) {
		this.x = another.x;
		this.y = another.y;
	}

	public void set(float x, float y) {
		this.x = x;
		this.y = y;
	}

	public void set(Coord coord) {
		this.x = coord.getX();
		this.y = coord.getY();
	}

	public void set(Coordinated coordinated, Mode mode) {
		if (mode == Mode.LOCATION) {
			this.set(coordinated.getLocation());
		} else {
			this.set(coordinated.getPosition());
		}
	}

	public void scale(float scale) {
		this.x *= scale;
		this.y *= scale;
	}

	public void add(PointF other) {
		this.x += other.x;
		this.y += other.y;
	}

	public void subtract(PointF other) {
		this.x -= other.x;
		this.y -= other.y;
	}

	public void normalize() {
		float length = (float) sqrt(pow(this.x, 2) + pow(this.y, 2));
		if (length != 0) {
			this.x /= length;
			this.y /= length;
		}
	}

	public void rotateCW() {
		float temp = x;
		x = y;
		y = -temp;
	}

	public float distanceTo(PointF other) {
		return (float) sqrt(pow(this.x - other.x, 2) + pow(this.y - other.y, 2));
	}

	public float distanceTo(Point other) {
		return (float) sqrt(pow(this.x - other.x, 2) + pow(this.y - other.y, 2));
	}

	public static float distance(PointF first, PointF second) {
		return (float) sqrt(pow(first.x - second.x, 2)
				+ pow(first.y - second.y, 2));
	}

	public static float distance(PointF first, Point second) {
		return (float) sqrt(pow(first.x - second.x, 2)
				+ pow(first.y - second.y, 2));
	}

	public static void difference(PointF first, PointF second, PointF result) {
		result.set(first.x - second.x, first.y - second.y);
	}

	public static PointF difference(PointF first, PointF second) {
		PointF result = new PointF();
		difference(first, second, result);
		return result;
	}

	public static void sum(PointF first, PointF second, PointF result) {
		result.set(first.x + second.x, first.y + second.y);
	}

	public static PointF sum(PointF first, PointF second) {
		PointF result = new PointF();
		sum(first, second, result);
		return result;
	}

	public static void averaged(PointF first, PointF second, PointF result) {
		result.set((first.x + second.x) / 2f, (first.y + second.y) / 2f);
	}

	public static PointF averaged(PointF first, PointF second) {
		PointF result = new PointF();
		averaged(first, second, result);
		return result;
	}

	public static void averaged(PointF first, PointF second, float firstWeight,
			float secondWeight, PointF result) {
		float weight = firstWeight + secondWeight;
		result.set((first.x * firstWeight + second.x * secondWeight) / weight,
				(first.y * firstWeight + second.y * secondWeight) / weight);
	}

	public static PointF averaged(PointF first, PointF second,
			float firstWeight, float secondWeight) {
		PointF result = new PointF();
		averaged(first, second, firstWeight, secondWeight, result);
		return result;
	}

	@Override
	public boolean equals(Object o) {
		if (o instanceof PointF) {
			PointF other = (PointF) o;
			return (this.x == other.x && this.y == other.y);
		} else {
			return false;
		}
	}

	public String toString() {
		return "(" + x + ";" + y + ")";
	}

}
